//-------------------------------------------------------------------------//
//                                                                         //
//  This benchmark is an OpenMP C version of the NPB LU code. This OpenMP  //
//  C version is developed by the Center for Manycore Programming at Seoul //
//  National University and derived from the OpenMP Fortran versions in    //
//  "NPB3.3-OMP" developed by NAS.                                         //
//                                                                         //
//  Permission to use, copy, distribute and modify this software for any   //
//  purpose with or without fee is hereby granted. This software is        //
//  provided "as is" without express or implied warranty.                  //
//                                                                         //
//  Information on NPB 3.3, including the technical report, the original   //
//  specifications, source code, results and information on how to submit  //
//  new results, is available at:                                          //
//                                                                         //
//           http://www.nas.nasa.gov/Software/NPB/                         //
//                                                                         //
//  Send comments or suggestions for this OpenMP C version to              //
//  cmp@aces.snu.ac.kr                                                     //
//                                                                         //
//          Center for Manycore Programming                                //
//          School of Computer Science and Engineering                     //
//          Seoul National University                                      //
//          Seoul 151-744, Korea                                           //
//                                                                         //
//          E-mail:  cmp@aces.snu.ac.kr                                    //
//                                                                         //
//-------------------------------------------------------------------------//

//-------------------------------------------------------------------------//
// Authors: Sangmin Seo, Jungwon Kim, Jun Lee, Jeongho Nah, Gangwon Jo,    //
//          and Jaejin Lee                                                 //
//-------------------------------------------------------------------------//

#include <stdio.h>
#include <math.h>
#include "applu.incl"
#include <mpi.h>

//---------------------------------------------------------------------
// 
// compute the solution error
// 
//---------------------------------------------------------------------
void error()
{


MPI_Status status;
   int my_id = 0, id_num = 0,upper_bound = 0, lower_bound = 0, pros_num = 0, average_span = 0, root_process=0;
   int ierr = 0;

   MPI_Comm comm;

   root_process = 0;

   ierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
   ierr = MPI_Comm_size(MPI_COMM_WORLD, &pros_num);

   average_span = ((nz-1)-1)/pros_num;

        if (my_id == root_process){

        lower_bound = 1;
        upper_bound = average_span;


           if ((my_id+1)  == pros_num){
                if(upper_bound < (nz0-2) ){
                        upper_bound = (nz0-2);
                   }
                }

         }
        else{
        lower_bound = (average_span *  my_id)+1 ;
        upper_bound = average_span * (my_id+1);

          if ((my_id+1) == pros_num){
                if(upper_bound < (nz0-2) ){
                        upper_bound = (nz0-2);
                   }
                 }
             }



  //---------------------------------------------------------------------
  // local variables
  //---------------------------------------------------------------------
  int i, j, k, m;
  double tmp;
  double u000ijk[5];
  double errnm_local[5];

  for (m = 0; m < 5; m++) {
    errnm[m] = 0.0;
  }
//TODO: mabey we can brodcast errnm like l2norm
//  #pragma omp parallel default(shared) private(i,j,k,m,tmp,u000ijk,errnm_local)
  {

  for (m = 0; m < 5; m++) {
    errnm_local[m] = 0.0;
  }


//printf("\n**\nthe last one is from 1 to %u and cal is from %u to %u span is %u \n**\n",nz-1,lower_bound,upper_bound,average_span);
//  #pragma omp for nowait
//  for (k = 1; k < nz-1; k++) {
  for(k = lower_bound; k <= upper_bound; k++){
    for (j = jst; j < jend; j++) {
      for (i = ist; i < iend; i++) {
        exact( i, j, k, u000ijk );
        for (m = 0; m < 5; m++) {
          tmp = ( u000ijk[m] - u[k][j][i][m] );
          errnm_local[m] = errnm_local[m] + tmp * tmp;
        }
      }
    }
  }


ierr=MPI_Allreduce( errnm_local,errnm, 5, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
/*  for (m = 0; m < 5; m++) {
    #pragma omp atomic
    errnm[m] += errnm_local[m];
  }
*/
  } //end parallel

  for (m = 0; m < 5; m++) {
    errnm[m] = sqrt ( errnm[m] / ( (nx0-2)*(ny0-2)*(nz0-2) ) );
  }

  /*
  printf(" \n RMS-norm of error in soln. to first pde  = %12.5E\n"
         " RMS-norm of error in soln. to second pde = %12.5E\n"
         " RMS-norm of error in soln. to third pde  = %12.5E\n"
         " RMS-norm of error in soln. to fourth pde = %12.5E\n"
         " RMS-norm of error in soln. to fifth pde  = %12.5E\n",
         errnm[0], errnm[1], errnm[2], errnm[3], errnm[4]);
  */
}

